/**
    \file usm_charset.c

    COPYRIGHT(C) 2009,ShenZhen smit CO.,LTD. \n
    All rights reserved. \n\n

    \brief implement the charset interface.

    \details charset interface includes:
        -
	\version 1.0
	\date 2012.6.16
	\author Wang Xiao rong
	\note Created
*/

/* Includes --------------------------------------------------------------- */
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <wchar.h>
#include "usm_typedef.h"

#include "usm_charset.h"
#include "usm_cs_extern.h"
#include "iso8859_to_unicode.h"
#include "unicode_to_iso8859.h"

/* Private Macros --------------------------------------------------------- */

/* Private Types ---------------------------------------------------------- */


/* Private Constants ------------------------------------------------------ */


/* Private Variables (static) --------------------------------------------- */

/* Global Variables ------------------------------------------------------- */
JZ_UINT16 nArrTableLen[USM_CS_FORMAT_END] = 
{
	0, 
	ISO8859_1_SIZE,  ISO8859_2_SIZE,  ISO8859_3_SIZE, 
	ISO8859_4_SIZE,  ISO8859_5_SIZE,  ISO8859_6_SIZE,  
	ISO8859_7_SIZE,  ISO8859_8_SIZE, ISO8859_9_SIZE,  
	ISO8859_10_SIZE, ISO8859_11_SIZE,  ISO8859_12_SIZE,  
	ISO8859_13_SIZE, ISO8859_14_SIZE,  ISO8859_15_SIZE,  
	ISO8859_16_SIZE, 
};

JZ_VOID* pvArrISO2UniTable[USM_CS_FORMAT_END] =
{
	 0, 0,
	ISO8859_2_to_Unicode_table,
	ISO8859_3_to_Unicode_table,
	ISO8859_4_to_Unicode_table,
	ISO8859_5_to_Unicode_table,
	ISO8859_6_to_Unicode_table,
	ISO8859_7_to_Unicode_table,
	ISO8859_8_to_Unicode_table,
	ISO8859_9_to_Unicode_table,
	ISO8859_10_to_Unicode_table,
	ISO8859_11_to_Unicode_table,
	0,
	ISO8859_13_to_Unicode_table,
	ISO8859_14_to_Unicode_table,
	ISO8859_15_to_Unicode_table,
	ISO8859_16_to_Unicode_table,
};


JZ_VOID* pvArrUni2ISOTable[USM_CS_FORMAT_END] =
{
	0, 0,
	Unicode_to_ISO8859_2_table,
	Unicode_to_ISO8859_3_table,
	Unicode_to_ISO8859_4_table,
	Unicode_to_ISO8859_5_table,
	Unicode_to_ISO8859_6_table,
	Unicode_to_ISO8859_7_table,
	Unicode_to_ISO8859_8_table,
	Unicode_to_ISO8859_9_table,
	Unicode_to_ISO8859_10_table,
	Unicode_to_ISO8859_11_table,
	0,
	Unicode_to_ISO8859_13_table,
	Unicode_to_ISO8859_14_table,
	Unicode_to_ISO8859_15_table,
	Unicode_to_ISO8859_16_table,
};

/* Private Function prototypes -------------------------------------------- */

/* Functions -------------------------------------------------------------- */

/**
    \fn JZ_Error_t USM_CS_Utf8len(const JZ_CHAR *pszString, JZ_INT32* pnLength)

    \brief Gets the length of a UTF-8 string.

    \param[in] pszString The UTF-8 string.
    \param[out] pnLength Pointer to store the length of the UTF-8 string on success.

    \retval JZ_SUCCESS Successful.
    \retval JZ_FAILURE Failed.
    \retval JZ_ERROR_BAD_PARAMETER Bad parameter passed.

    \remark
     * UNICODE -                           UTF-8
     *00000000 ~ 0000007F           0xxxxxxx
     *00000080 ~ 000007FF           110xxxxx 10xxxxxx
     *00000800 ~ 0000FFFF           1110xxxx 10xxxxxx 10xxxxxx
     *00010000 ~ 001FFFFF           11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
     *00200000 ~ 03FFFFFF           111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
     *04000000 ~ 7FFFFFFF           1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
JZ_Error_t USM_CS_Utf8len(const JZ_CHAR *pszString, JZ_INT32* pnLength)
{	
	USM_ENTER();
	
	USM_VERIFY(pszString != JZ_NULL);
	USM_VERIFY(pnLength != JZ_NULL);

	*pnLength = 0;
	
	while (*pszString)
	{
		if (((*pszString) & 0x80) == 0)        /**<  0xxxxxxx */
		{
			pszString += 1;
		}
		else if (((*pszString) & 0xE0) == 0xC0)/**< 110xxxxx 10xxxxxx */
		{
			pszString += 2;
		}
		else if (((*pszString) & 0xF0) == 0xE0)/**< 1110xxxx 10xxxxxx 10xxxxxx */
		{
			pszString += 3;
		}
		else if (((*pszString) & 0xf8) == 0xF0)/**< 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
		{
			pszString += 4;
		}
		else if (((*pszString) & 0xfc) == 0xF8)/**< 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
		{
			pszString += 5;
		}
		else if (((*pszString) & 0xfe) == 0xFC)/**1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
		{
			pszString += 6;
		}
		else
		{
			pszString += 1;
			continue;
		}

		(*pnLength)++;
	}

	return(JZ_SUCCESS);
}

/**
    \fn JZ_Error_t USM_CS_Utf82Unicode(JZ_WCHAR *pwszDest, const JZ_CHAR *pszSrc, JZ_INT32 nLength)

    \brief Converts a UTF-8 string into a Unicode string.

    \param[out] pwszDest The destination wide-character string.
    \param[in] pszSrc The source string which charset format is UTF-8.
    \param[in] nLength The length of the source string. The value of 0 represents the source string ends with a null character.

    \retval JZ_SUCCESS Successful.
    \retval JZ_FAILURE Failed.
    \retval JZ_ERROR_BAD_PARAMETER Bad parameter passed.

    \remark

    \see USM_CS_Unicode2Utf8
*/
JZ_Error_t USM_CS_Utf82Unicode(JZ_WCHAR *pwszDest, const JZ_CHAR *pszSrc, JZ_INT32 nLength)
{

	JZ_INT32 		nOffsetDestBuf = 0;
	JZ_INT32 		nOffsetSrcBuf;
	JZ_INT16 		nTmp1, nTmp2;
	JZ_UCHAR 	ucByte1, ucByte2, ucByte3;

	USM_ENTER();

	USM_VERIFY(pwszDest != JZ_NULL);
	USM_VERIFY(pszSrc != JZ_NULL);

	for (nOffsetSrcBuf = 0; nOffsetSrcBuf < nLength;)
	{
		ucByte1 = pszSrc[nOffsetSrcBuf];

		if (isHeadOfOneByteChar(ucByte1))/**<  0xxxxxxx */
		{
			pwszDest[nOffsetDestBuf++] = ucByte1;
			nOffsetSrcBuf++;
		}
		else if (isHeadOfTwoBytesChar(ucByte1)) /**< 110xxxxx 10xxxxxx */
		{
			if ((nOffsetSrcBuf + 2) > nLength)
			{
				pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
				break;
			}

			ucByte2 = pszSrc[nOffsetSrcBuf + 1];
			if (isComingByteOfMultBytesChar(ucByte2))
			{
				nTmp1 = ucByte1 & 0x1F;
				nTmp1 = (nTmp1 << 6) + (ucByte2 & 0x3F);
				pwszDest[nOffsetDestBuf++] = nTmp1;
				nOffsetSrcBuf += 2;
			}
			else if (isHeadOfUTF8Char(ucByte2))
			{
				pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
				nOffsetSrcBuf += 1;
			}
			else
			{
				pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
				nOffsetSrcBuf += 2;
			}
		}
		else if (isHeadOfThreeBytesChar(ucByte1)) /**< 1110xxxx 10xxxxxx 10xxxxxx */
		{
			if ((nOffsetSrcBuf + 2) > nLength)
			{
				pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
				break;
			}
			else if ((nOffsetSrcBuf + 3) > nLength)
			{
				ucByte2 = pszSrc[nOffsetSrcBuf + 1];
				if (isHeadOfOneByteChar(ucByte2))
				{
					pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
					nOffsetSrcBuf += 1;

					continue;
				}
				else
				{

					pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;

					break;
				}
			}


			ucByte2 = pszSrc[nOffsetSrcBuf + 1];
			ucByte3 = pszSrc[nOffsetSrcBuf + 2];
			if (isComingByteOfMultBytesChar(ucByte2) && isComingByteOfMultBytesChar(ucByte3))
			{
				nTmp1 = ucByte1 & 0x0F;
				nTmp1 = nTmp1 << 12;
				nTmp2 = ucByte2 & 0x3F;
				nTmp2 = nTmp2 << 6;
				pwszDest[nOffsetDestBuf++] = nTmp1 + nTmp2 + (ucByte3 & 0x3F);
				nOffsetSrcBuf += 3;
			}
			else if (isHeadOfUTF8Char(ucByte2))
			{
				pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
				nOffsetSrcBuf += 1;
			}
			else if (isHeadOfUTF8Char(ucByte3))
			{
				pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
				nOffsetSrcBuf += 2;
			}
			else
			{
				pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
				nOffsetSrcBuf += 3;
			}
		}
		else
		{

			pwszDest[nOffsetDestBuf++] = UNSUPPORTED_CHAR;
			nOffsetSrcBuf += 1;
		}
	}

	pwszDest[nOffsetDestBuf] = '\0';

	return(JZ_SUCCESS);
}

/**
    \fn JZ_Error_t USM_CS_Unicode2Utf8(JZ_CHAR *pszDest, const JZ_WCHAR *pwszSrc, JZ_INT32 nLength)

    \brief Converts a Unicode string into a UTF-8 string.

    \param[out] pszDest The destination UTF-8 string.
    \param[in] pwszSrc The source wide-character string.
    \param[in] nLength The length of the source wide-character string. The value of 0 represents the source wide-character string ends with a null character.

    \retval JZ_SUCCESS Successful.
    \retval JZ_FAILURE Failed.
    \retval JZ_ERROR_BAD_PARAMETER Bad parameter passed.

    \remark

     * UNICODE -                           UTF-8
     *00000000 ~ 0000007F           0xxxxxxx
     *00000080 ~ 000007FF           110xxxxx 10xxxxxx
     *00000800 ~ 0000FFFF           1110xxxx 10xxxxxx 10xxxxxx
     *00010000 ~ 001FFFFF           11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
     *00200000 ~ 03FFFFFF           111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
     *04000000 ~ 7FFFFFFF           1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

    \see USM_CS_Utf82Unicode
*/
JZ_Error_t USM_CS_Unicode2Utf8(JZ_CHAR *pszDest, const JZ_WCHAR *pwszSrc, JZ_INT32 nLength)
{
	JZ_INT32    nOffsetSrcBuf = 0;
	JZ_INT32    nOffsetDestBuf = 0;

	USM_ENTER();
	
	USM_VERIFY(pwszSrc != JZ_NULL);
	USM_VERIFY(pszDest != JZ_NULL);
	USM_VERIFY(nLength > 0);
	
	for (nOffsetSrcBuf = 0;nOffsetSrcBuf <  nLength;nOffsetSrcBuf++)
	{
		if ((*(pwszSrc + nOffsetSrcBuf) <= 0x7f))
		{
			*(pszDest + nOffsetDestBuf) = 0x7f & (*(pwszSrc + nOffsetSrcBuf));
			nOffsetDestBuf++;

		}
		else if ((*(pwszSrc + nOffsetSrcBuf) >= 0x80) && (*(pwszSrc + nOffsetSrcBuf) <= 0x7ff))
		{

			*(pszDest + nOffsetDestBuf) = ((*(pwszSrc + nOffsetSrcBuf) >> 6) & 0x1f) | 0xC0;
			nOffsetDestBuf++;
			
			*(pszDest + nOffsetDestBuf) = ((*(pwszSrc + nOffsetSrcBuf)) & 0x3f) | 0x80;
			nOffsetDestBuf++;

		}
		else if ((*(pwszSrc + nOffsetSrcBuf) >= 0x800))
		{
			*(pszDest + nOffsetDestBuf) = (((*(pwszSrc + nOffsetSrcBuf)) >> 12) & 0xf) | 0xe0;
			nOffsetDestBuf++;

			*(pszDest + nOffsetDestBuf) = (((*(pwszSrc + nOffsetSrcBuf)) >> 6) & 0x3f) | 0x80;
			nOffsetDestBuf++;

			*(pszDest + nOffsetDestBuf) = ((*(pwszSrc + nOffsetSrcBuf)) & 0x3f) | 0x80;
			nOffsetDestBuf++;
		}
	}

	*(pszDest + nOffsetDestBuf) = 0;

	return(JZ_SUCCESS);
}
JZ_Error_t USM_CS_Unicode2Utf8_ext(JZ_CHAR *pszDest, const JZ_CHAR *pwszSrc, JZ_INT32 nLength)
{
	JZ_INT32    nOffsetSrcBuf = 0;
	JZ_INT32    nOffsetDestBuf = 0;

	USM_ENTER();
	
	USM_VERIFY(pwszSrc != JZ_NULL);
	USM_VERIFY(pszDest != JZ_NULL);
	USM_VERIFY(nLength > 0);
	
	for (nOffsetSrcBuf = 0;nOffsetSrcBuf <  nLength;nOffsetSrcBuf++)
	{
		if ((*(pwszSrc + nOffsetSrcBuf) <= 0x7f))
		{
			*(pszDest + nOffsetDestBuf) = 0x7f & (*(pwszSrc + nOffsetSrcBuf));
			nOffsetDestBuf++;

		}
		else if ((*(pwszSrc + nOffsetSrcBuf) >= 0x80) && (*(pwszSrc + nOffsetSrcBuf) <= 0x7ff))
		{

			*(pszDest + nOffsetDestBuf) = ((*(pwszSrc + nOffsetSrcBuf) >> 6) & 0x1f) | 0xC0;
			nOffsetDestBuf++;
			
			*(pszDest + nOffsetDestBuf) = ((*(pwszSrc + nOffsetSrcBuf)) & 0x3f) | 0x80;
			nOffsetDestBuf++;

		}
		else if ((*(pwszSrc + nOffsetSrcBuf) >= 0x800))
		{
			*(pszDest + nOffsetDestBuf) = (((*(pwszSrc + nOffsetSrcBuf)) >> 12) & 0xf) | 0xe0;
			nOffsetDestBuf++;

			*(pszDest + nOffsetDestBuf) = (((*(pwszSrc + nOffsetSrcBuf)) >> 6) & 0x3f) | 0x80;
			nOffsetDestBuf++;

			*(pszDest + nOffsetDestBuf) = ((*(pwszSrc + nOffsetSrcBuf)) & 0x3f) | 0x80;
			nOffsetDestBuf++;
		}
	}

	*(pszDest + nOffsetDestBuf) = 0;

	return(JZ_SUCCESS);
}


/**
    \fn JZ_Error_t USM_CS_ISO2Unicode(JZ_WCHAR *pwszDest, const JZ_CHAR *pszSrc, USM_CS_Format_t format, JZ_INT32 nLength)

    \brief Converts an ISO 8859 encoded string into a Unicode string.

    \param[out] pwszDest The destination wide-character string.
    \param[in] pszSrc The source string which charset format is a member of the ISO 8859 family.
    \param[in] format The charset format in the ISO 8859 family.
    \param[in] nLength The length of the source string. The value of 0 represents the source string ends with a null character.

    \retval JZ_SUCCESS Successful.
    \retval JZ_FAILURE Failed.
    \retval JZ_ERROR_BAD_PARAMETER Bad parameter passed.

    \remark

    \see USM_CS_Unicode2ISO
*/
JZ_Error_t USM_CS_ISO2Unicode(JZ_WCHAR *pwszDest, const JZ_CHAR *pszSrc, USM_CS_Format_t format, JZ_INT32 nLength)
{
	JZ_UINT16 nTemp;
	JZ_UINT16  nIndex = 0;

	USM_ENTER();
	
	USM_VERIFY(pszSrc != JZ_NULL);
	USM_VERIFY(pwszDest != JZ_NULL);
	USM_VERIFY(format < USM_CS_FORMAT_END);
	USM_VERIFY(format >= USM_CS_ISO8859_1);

	switch (format)
	{
		case USM_CS_ISO8859_1:               /**< West European. */
		{
			while (*pszSrc)
			{
				pwszDest[nIndex++] = ((*pszSrc) & 0x00ff);
				pszSrc += 1;
			}
			pwszDest[nIndex] = 0x00;
		}
		break;

		case USM_CS_ISO8859_2:               /**< Central and East European. */
		case USM_CS_ISO8859_3:               /**< South European, Maltese & Esperanto. */
		case USM_CS_ISO8859_4:               /**< North European. */
		case USM_CS_ISO8859_5:               /**< Slavic languages. */
		case USM_CS_ISO8859_6:               /**< Arabic. */
		case USM_CS_ISO8859_7:               /**< Modern Greek. */
		case USM_CS_ISO8859_8:               /**< Hebrew and Yiddish. */
		case USM_CS_ISO8859_9:              /**< Turkish. */
		case USM_CS_ISO8859_10:              /**< Nordic. */
		case USM_CS_ISO8859_11:              /**< Thai. */
		case USM_CS_ISO8859_13:              /**< Baltic Rim. */
		case USM_CS_ISO8859_14:              /**< Celtic. */       
		case USM_CS_ISO8859_15:              /**< Adds euro to 8859-1 (8 changes. */
		case USM_CS_ISO8859_16:              /**< South-Eastern Europe. */    
		{
			while (*pszSrc)
			{
				if ((JZ_UCHAR)(*pszSrc) > 0xA0)
				{
					USM_CS_GetMatchedCode(pvArrISO2UniTable[format], nArrTableLen[format], (*pszSrc)& 0x00ff, &nTemp);
					pwszDest[nIndex] =  nTemp;
				}
				else
				{
					pwszDest[nIndex] = (*pszSrc)& 0x00ff;
				}

				pszSrc += 1;
				nIndex++;
			}

			pwszDest[nIndex] = 0x00;
		}
		break;


		case USM_CS_ISO8859_12:              /**< Not been defined. */
		{
			return( JZ_ERROR_BAD_PARAMETER);
		}
		break;
		default:
		{
			return( JZ_ERROR_BAD_PARAMETER);
		}
		break;
	}

	return(JZ_SUCCESS);
}

/**
    \fn JZ_Error_t USM_CS_Unicode2ISO(JZ_CHAR *pszDest, USM_CS_Format_t format, const JZ_WCHAR *pwszSrc, JZ_INT32 nLength)

    \brief Converts a Unicode string into an ISO 8859 encoded string.

    \param[out] pszDest The destination string which charset format is a member of the ISO 8859 family.
    \param[in] format The charset format in the ISO 8859 family.
    \param[in] pwszSrc The source wide-character string.
    \param[in] nLength The length of the source wide-character string. The value of 0 represents the source wide-character string ends with a null character.

    \retval JZ_SUCCESS Successful.
    \retval JZ_FAILURE Failed.
    \retval JZ_ERROR_BAD_PARAMETER Bad parameter passed.

    \remark

    \see USM_CS_ISO2Unicode
*/
JZ_Error_t USM_CS_Unicode2ISO(JZ_CHAR *pszDest, USM_CS_Format_t format, const JZ_WCHAR *pwszSrc, JZ_INT32 nLength)
{
	JZ_UINT16	 nTemp;
	JZ_INT16 		 nIndex = 0;

	USM_ENTER();
	
	USM_VERIFY(pwszSrc != JZ_NULL);
	USM_VERIFY(pszDest != JZ_NULL);
	USM_VERIFY(format < USM_CS_FORMAT_END);
	USM_VERIFY(format >= USM_CS_ISO8859_1);

	switch (format)
	{
		case USM_CS_ISO8859_1:               /**< West European. */
		{
			while (*pwszSrc)
			{
				pszDest[nIndex++] = (JZ_UCHAR) (*pwszSrc);
				pwszSrc += 1;
			}
			pszDest[nIndex] = 0x00;
		}
		break;

		case USM_CS_ISO8859_2:               /**< Central and East European. */
		case USM_CS_ISO8859_3:               /**< South European, Maltese & Esperanto. */
		case USM_CS_ISO8859_4:               /**< North European. */
		case USM_CS_ISO8859_5:               /**< Slavic languages. */
		case USM_CS_ISO8859_6:               /**< Arabic. */
		case USM_CS_ISO8859_7:               /**< Modern Greek. */
		case USM_CS_ISO8859_8:               /**< Hebrew and Yiddish. */
		case USM_CS_ISO8859_9:              /**< Turkish. */
		case USM_CS_ISO8859_10:              /**< Nordic. */
		case USM_CS_ISO8859_11:              /**< Thai. */
		case USM_CS_ISO8859_13:              /**< Baltic Rim. */
		case USM_CS_ISO8859_14:              /**< Celtic. */       
		case USM_CS_ISO8859_15:              /**< Adds euro to 8859-1 (8 changes. */
		case USM_CS_ISO8859_16:              /**< South-Eastern Europe. */  
		{
			while (*pwszSrc)
			{
				if ((*pwszSrc) > 0xA0)
				{
					USM_CS_GetMatchedCode(pvArrUni2ISOTable[format], nArrTableLen[format], (*pwszSrc), &nTemp);
					pszDest[nIndex] =  (JZ_UCHAR)nTemp;
				}
				else
				{
					pszDest[nIndex] = (JZ_UCHAR) (*pwszSrc);
				}

				pwszSrc += 1;
				nIndex++;
			}

			pszDest[nIndex] = 0x00;
		}
		break;

		case USM_CS_ISO8859_12:              /**< Not been defined. */
		{
			return( JZ_ERROR_BAD_PARAMETER);
		}
		break;
		default:
		{
			return( JZ_ERROR_BAD_PARAMETER);
		}
		break;

	}

	return(JZ_SUCCESS);

}

/**
    \fn JZ_Error_t USM_CS_Str2Unicode(JZ_WCHAR *pwszDest, const JZ_CHAR *pszSrc, USM_CS_Format_t format, JZ_INT32 nLength)

    \brief Converts a string into a unicode string.

    \param[out] pwszDest The destination wide-character string.
    \param[in] pszSrc The source string which charset format is \a format.
    \param[in] format The charset format.
    \param[in] nLength The length of the source string. The value of 0 represents the source string ends with a null character.

    \retval JZ_SUCCESS Successful.
    \retval JZ_FAILURE Failed.
    \retval JZ_ERROR_BAD_PARAMETER Bad parameter passed.

    \remark
*/
JZ_Error_t USM_CS_Str2Unicode(JZ_WCHAR *pwszDest, const JZ_CHAR *pszSrc, USM_CS_Format_t format, JZ_INT32 nLength)
{
	JZ_Error_t JZ_ErrType = JZ_FAILURE;

	USM_ENTER();
	
	USM_VERIFY(pszSrc != JZ_NULL);
	USM_VERIFY(pwszDest != JZ_NULL);
	USM_VERIFY(nLength > 0);

	switch (format)
	{
		case  USM_CS_UNICODE:                /**< ISO/IEC 10646-1. */
		{
			memcpy((JZ_CHAR *)pwszDest, pszSrc, nLength);
			JZ_ErrType = JZ_SUCCESS;
		}
		break;

		case USM_CS_UTF8:                    /**< RFC 3629. */
		{
			JZ_ErrType = USM_CS_Utf82Unicode(pwszDest, pszSrc, nLength);
		}
		break;

		case USM_CS_GB2312:                  /**< Chinese GB2312. */
		{
			JZ_ErrType = USM_CS_GB2Unicode(pwszDest, pszSrc, nLength);
		}
		break;

		case USM_CS_BIG5:                    /**< Chinese Big5. */
		{
			JZ_ErrType = USM_CS_Big52Unicode(pwszDest, pszSrc, nLength);
		}
		break;

		case USM_CS_KSC:                    /**< Korean KSC. */
		{
			JZ_ErrType = USM_CS_KSC2Unicode(pwszDest, pszSrc, nLength);
		}
		break;

		case USM_CS_JIS:                     /**< Japanese JIS. */
		{
			JZ_ErrType = USM_CS_JIS2Unicode(pwszDest, pszSrc, nLength);
		}
		break;

		case USM_CS_GBK:
		{
			JZ_ErrType = USM_CS_GBK2Unicode(pwszDest, pszSrc, nLength);
		}
		break;
		
		default:                                 /**< ISO8859 family */
		{
			JZ_ErrType = USM_CS_ISO2Unicode(pwszDest, pszSrc, format, nLength);
		}
		break;

	}
	return(JZ_ErrType);
}

/**
    \fn JZ_Error_t USM_CS_Unicode2Str(JZ_CHAR *pszDest, USM_CS_Format_t format, const JZ_WCHAR *pwszSrc, JZ_INT32 nLength)

    \brief Converts a Unicode string into a string encoded in the specified character set.

    \param[out] pszDest The destination string which charset format is \a format.
    \param[in] pwszSrc The source wide-character string.
    \param[in] format The charset format.
    \param[in] nLength The length of the source wide-character string. The value of 0 represents the source wide-character string ends with a null character.

    \retval JZ_SUCCESS Successful.
    \retval JZ_FAILURE Failed.
    \retval JZ_ERROR_BAD_PARAMETER Bad parameter passed.

    \remark

    \see USM_CS_Str2Unicode
*/
JZ_Error_t USM_CS_Unicode2Str(JZ_CHAR *pszDest, USM_CS_Format_t format, const JZ_WCHAR *pwszSrc, JZ_INT32 nLength)
{
	JZ_Error_t JZ_ErrType = JZ_FAILURE;

	USM_ENTER();
	
	USM_VERIFY(pwszSrc != JZ_NULL);
	USM_VERIFY(pszDest != JZ_NULL);
	USM_VERIFY(nLength > 0);

	switch (format)
	{
		case  USM_CS_UNICODE:                /**< ISO/IEC 10646-1. */
		{
			memcpy(pszDest, (JZ_CHAR *)pwszSrc, nLength * sizeof(JZ_WCHAR));
			JZ_ErrType = JZ_SUCCESS;
		}
		break;

		case USM_CS_UTF8:                    /**< RFC 3629. */
		{
			JZ_ErrType = USM_CS_Unicode2Utf8(pszDest, pwszSrc, nLength);
		}
		break;

		case USM_CS_GB2312:                  /**< Chinese GB2312. */
		{
			JZ_ErrType = USM_CS_Unicode2GB(pszDest, pwszSrc, nLength);
		}
		break;

		case USM_CS_BIG5:                    /**< Chinese Big5. */
		{
			JZ_ErrType = USM_CS_Unicode2Big5(pszDest, pwszSrc, nLength);
		}
		break;

		case USM_CS_KSC:                    /**< Korean KSC. */
		{
			JZ_ErrType = USM_CS_Unicode2KSC(pszDest, pwszSrc, nLength);
		}
		break;

		case USM_CS_JIS:                     /**< Japanese JIS. */
		{
			JZ_ErrType = USM_CS_Unicode2JIS(pszDest, pwszSrc, nLength);
		}
		break;

		default:                                 /**< ISO8859 family */
		{
			JZ_ErrType = USM_CS_Unicode2ISO(pszDest, format, pwszSrc, nLength);
		}
		break;

	}
	return(JZ_ErrType);
}

/**
    \fn JZ_Error_t USM_CS_GetMatchedCode(JZ_UINT16 nMappingTable[][2], JZ_UINT16 nTableLen, JZ_UINT16 nCode, JZ_UINT16 *pnMatchedCode)
    \brief binary_search in 2D char-map array

    \param[in]  nMappingTable : a 2D character-map array.
    \param[in]  nTableLen : number of character-pair in table
    \param[in]  nCode : code of character to search in table
    \param[out]  pnMatchedCode : pointer to store the matched code if success.

    \retval JZ_SUCCESS Successful.
    \retval JZ_FAILURE Failed.
    \remark

*/
JZ_Error_t USM_CS_GetMatchedCode(JZ_UINT16 nMappingTable[][2], JZ_UINT16 nTableLen, JZ_UINT16 nCode, JZ_UINT16 *pnMatchedCode)
{
	JZ_UINT16  nHead = 0;
	JZ_UINT16  nTail;
	JZ_UINT16  nMiddle;

	USM_ENTER();

	USM_VERIFY(nMappingTable[nHead][0] <= nCode);
    USM_VERIFY(nCode <= nMappingTable[nTail][0]);

	nTail = nTableLen - 1;
	*pnMatchedCode = (UNSUPPORTED_CHAR);

	while (nHead <= nTail)
	{
		nMiddle = (nHead + nTail) >> 1;
		if (nCode == nMappingTable[nMiddle][0])
		{
			*pnMatchedCode = (nMappingTable[nMiddle][1]);
			return(JZ_SUCCESS);
		}
		else if (nCode > nMappingTable[nMiddle][0])
		{
			nHead = nMiddle + 1;
		}
		else
		{
			nTail = nMiddle - 1;
		}
	}

	return(JZ_FAILURE);
}

JZ_Error_t USM_CS_IsUtf8(JZ_CHAR *pString)
{
	JZ_INT32    nOffsetSrcBuf = 0;
	JZ_INT32    Utfflag = 0;
	for (nOffsetSrcBuf = 0;nOffsetSrcBuf <  7;nOffsetSrcBuf++)
	{
		if ((*(pString + nOffsetSrcBuf)&0xC0 == 0xc0)
			&&(*(pString + nOffsetSrcBuf+1)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+2)&0x80 != 0x80))
		{
			Utfflag = 1;
			break;
		}	
		else if ((*(pString + nOffsetSrcBuf)&0xE0 == 0xE0)
			&& (*(pString + nOffsetSrcBuf+1)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+2)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+3)&0x80 != 0x80))
		{
			Utfflag = 1;
			break;
		}
		else if ((*(pString + nOffsetSrcBuf)&0xF0 == 0xF0) 
			&& (*(pString + nOffsetSrcBuf+1)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+2)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+3)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+4)&0x80 != 0x80))
		{
			Utfflag = 1;
			break;
		}
		else if ((*(pString + nOffsetSrcBuf)&0xF8 == 0xF8) 
			&& (*(pString + nOffsetSrcBuf+1)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+2)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+3)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+4)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+5)&0x80 != 0x80))
		{
			Utfflag = 1;
			break;
		}
		else if ((*(pString + nOffsetSrcBuf)&0xFC == 0xFC) 
			&& (*(pString + nOffsetSrcBuf+1)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+2)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+3)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+4)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+5)&0x80 == 0x80)
			&&(*(pString + nOffsetSrcBuf+6)&0x80 != 0x80))
		{
			Utfflag = 1;
			break;
		}
		nOffsetSrcBuf ++;
	}
	return Utfflag;
}
